<?php
require_once("Entity.php");

/**
 * @author Matteo Vigoni
 * @package DBEntity
 * @version 0.1 [modified for Sandro Del Pistoia]
 */
class DBEntity implements Entity
{
	/**
	 * @var $primary_key il nome del campo che identifica la chiave primaria
	 * @var $id il valore della chiave primaria
	 *
	 * @var $ext_id
	 */
	private $id = null;
	private $ext_id = null;

	public $values = Array();
	public $changes = Array();
	public $is_new = true;

	public $db_wrapper;
	public $table = null;
	public $primary_key;

	// commit
	private $commit_query_update = "UPDATE ";
	private $commit_query_set = "SET ";
	private $commit_query_where = "WHERE ";

	/**
	 * Costruttore
	 *
	 * @param DB $db_wrapper
	 * @param string $table nome della tabella
	 * @param string $primary_key il nome del campo della chiave primaria
	 *
	 * @throws DBException se si sono verificati problemi durante l'interrogazione con il database
	 *
	 * @todo implementazione di chiavi primarie multiple da realizzare con due array $pk e $kv che contengono
	 * 			i nomi e i valori delle chiavi primarie.
	 */
	function __construct(DB $db_wrapper, $table, $primary_key, $id=null)
		{
		$this->db_wrapper = $db_wrapper;
		$this->table = $table;
		$this->primary_key = $primary_key;

		if(isset($id))
		{
			$this->id = $id;

			$mysql_query = 	"SELECT * " .
				"FROM $table " .
				"WHERE $primary_key=$id ";

			$result = $this->db_wrapper->query($mysql_query);
			$data_array = mysql_fetch_assoc($result);

			if(!$data_array) throw new EntityException("L'elemento di indice ".$id." non esiste");
			//var_dump($data_array);
			foreach($data_array as $key => $value)
			{
				$this->values[$key] = $value;
			}

			$this->is_new = false;
		}
		}

	/**
	 * Restituisce il valore corrispondente alla chiave primaria
	 *
	 * @return string l'identificativo unico per qesto DBEntity
	 */
	public function getId()
		{
		return $this->id;
		}

	/**
	 * Restituisce l' XML realativo a questa entita'.
	 * I nomi dei tag sono i nomi del relativo campo.
	 *
	 * @todo metodo ancora da testare
	 */
	public function getXML()
		{
		$xml = "<$this->table>";

		foreach($this->values as $key => $value){
			$xml .= "<$key>$value</$key>";
		}

		$xml .= "</$this->table>";

		return $xml;
		}

	/**
	 *
	 * @return una stringa in formato JSON
	 */
	public function getJSON()
		{
		$json = "{\n";
		$nelem = count($this->values);
		$i = 0;

		foreach($this->values as $key => $value){
			$json .= "\t\"$key\":\"$value\"";
			$i++;
			if($i<$nelem) $json.= ",\n";
		}

		return $json."\n}";
		}

	/**
	 * @param string $index il nome del campo
	 */
	public function get($index)
	{
		if(!isset($this->values[$index]))
			throw new EntityException("Non esiste nessun valore per ".$index);
			
		return eregi_replace("\n", "<br />", $this->values[$index]);
	}

	/**
	 * Setta/Modifica il valore di un campo del record, questa modifica viene effettuata solo sull'oggetto
	 * per applicare tutte le modifiche anche su database si deve chiamare la funzione commit()
	 *
	 * @param $index
	 * @param $value
	 */
	public function set($index, $value)
	{
		if(is_string($value))
		{
		 	$value = trim($value);
		 	$value = stripslashes($value);
		 	$value = htmlspecialchars($value);
		}
		$this->values[$index] = $value;
		$this->changes[$index] = true;
	}

	/**
	 * Applica le modifiche apportate al record individuato dalla chiave primaria $primary_key
	 */
	public function commit()
		{
		$toSet = $this->commit_query_set;
		$first = TRUE; # variabile usata per posizionare le virgole

		foreach($this->changes as $key => $val){ # iterazione all'interno dell'array

			if($val){

				if($first) {					#
					$first = FALSE;				# Corretto posizionamento della virgola
				} else $toSet = $toSet . ", ";	#

				# viene aggiornato solo il valore cambiato
				$toSet = $toSet . "`" . $key . "`='" . $this->values[$key] . "'";
			}

		}

		$toSet = $toSet . " ";
		//echo $toSet . "<br />";	# stampa di verifica

		$query = $this->commit_query_update . $this->table . " "
			. $toSet
			. $this->commit_query_where . "`{$this->table}`.`{$this->primary_key}`='" . $this->getId()
			. "' LIMIT 1";

		//echo $query . "<br />";	# stampa di verifica
		$this->db_wrapper->query($query);
		$this->reset();
		}

	/**
	 * Inserisce nella tabella un nuovo record con parametri settati in precedenza
	 *
	 * @param $id il valore della chiave primaria dell'elemento che sta per essere scritto nel database
	 * 			di default questo valore e' impostato a null, in questo caso tratta l'id corrispondente
	 * 			come AUTO_INCREMENT
	 *
	 * @trows EntityException se la chiave primaria e' gie' definita oppure se e' occorso un errore
	 * 							durante la scrittura nel database.
	 */
	public function store($id=null)
		{
		$mysql_query_insert = "INSERT INTO `{$this->db_wrapper->name()}`.`$this->table` (";
		$mysql_query_values = ")VALUES (";

		//echo "sid: ".$id . "<br />";

		$mysql_query_insert .= $this->primary_key . ", ";
		if(is_null($id)) $mysql_query_values .= "NULL, ";
		else {
			if(is_string($id)) $mysql_query_values .= "'$id', ";
			else $mysql_query_values .= "$id, ";
		}

		$size = count($this->values);

		$i = 1;
		foreach($this->values as $key => $value){

			$mysql_query_insert .= $key;

			if(is_string($value)) $mysql_query_values .= "'$value'";
			else $mysql_query_values .= $value;

			if($i < $size){
				$mysql_query_insert .= ", ";
				$mysql_query_values .= ", ";
			}
			$i++;
		}

		$mysql_query = $mysql_query_insert . $mysql_query_values . ");";
		//echo $mysql_query;

		try{
			//scrivo i cambiamenti sul database
			$result = $this->db_wrapper->query($mysql_query);
			if(is_null($id)) $this->id = mysql_insert_id();
			else $this->id = $id;
			//echo "ID ".$this->id."<br />";

		} catch (DBException $e){
			throw new EntityException($e->getMessage());
		}

		//resetto tutti i valori ausiliari
		$this->reset();
		}

	/**
	 * Elimina questo record dal database
	 *
	 * @throws DBException
	 */
	public function cancel()
		{
		$mysql_query = "DELETE FROM `$this->table` WHERE `$this->table`.`$this->primary_key` = $this->id LIMIT 1";
		$this->db_wrapper->query($mysql_query);
		}

	/**
	 * Resetta tutte le variabili di ausilio.
	 */
	private function reset()
		{
		$this->commit_query_set = "SET ";
		$this->commit_query_update = "UPDATE ";
		$this->commit_query_where = "WHERE ";

		foreach ( $this->changes as $key => $value ) {
			$this->changes[$key] = false;
		}
		}

	/**
	 * Conta il numero di record presenti in questa tabella
	 *
	 * @param DB $db_wrapper
	 * @param $table_name
	 *
	 * @return il numero di record nel database
	 */
	public static function count(DB $db_wrapper, $table_name)
		{
		$mysql_query = "SELECT count(*) FROM ".$table_name." WHERE 1";
		$data = mysql_fetch_row($db_wrapper->query($mysql_query));

		return $data[0];
		}

	/**
	 * Restituisce il record nella tabella $table_name identificato dalla chiave $id
	 *
	 * @param DB $db_wrapper
	 * @param $table_name
	 * @param $primary_key
	 * @param $id
	 *
	 * @return
	 */
	public static function getFromId(DB $db_wrapper, $table_name, $primary_key, $id)
		{
		return new DBEntity($db_wrapper, $table_name, $primary_key, $id);
		}

	/**
	 * Restituisce l'XML relativo al record nella tabella $table_name identificato dalla chiave $id
	 *
	 * @param DB $db_wrapper
	 * @param $table_name
	 * @param $primary_key
	 * @param $id
	 *
	 * @return il contenuto xml realativo a la record identificato da $id
	 */
	public static function getXMLFromId(DB $db_wrapper, $table_name, $prymary_key ,$id)
		{
		$mysql_query = 	"SELECT * " .
			"FROM $table_name " .
			"WHERE $primary_key=$id ";

		$xml = "<$table_name>";

		try{
			$data = mysql_fetch_assoc($db_wrapper->query($mysql_query));

			foreach($data as $key => $value){
				$xml .= "<$key>$value</$key>";
			}
		}catch (DBException $e){
			throw new EntityException($e->getMessage());
		}

		$xml .= "</$table_name>";

		return $xml;
		}

	/**
	 * Restituisce il JSON relativo al record nella tabella $table_name identificato dalla chiave $id
	 *
	 * @param DB $db_wrapper
	 * @param $table_name
	 * @param $primary_key
	 * @param $id
	 *
	 * @return string il contenuto json realativo a la record identificato da $id
	 */
	public static function getJSONFromId(DB $db_wrapper, $table_name, $primary_key, $id)
		{
		$mysql_query = 	"SELECT * " .
			"FROM $table_name " .
			"WHERE $primary_key=$id ";

		$json = "{\n";

		try{
			$data = mysql_fetch_assoc($db_wrapper->query($mysql_query));

			$nelem = count($data);
			$i = 0;

			foreach($data as $key => $value){
				$json .= "\t\"$key\":\"".eregi_replace("\n", "<br />", $value)."\"";
				$i++;
				if($i<$nelem) $json.= ",\n";
			}
		}catch (DBException $e){
			throw new EntityException($e->getMessage());
		}

		$json .= "\n}";

		return $json;
		}
}
?>
